import java.io.*;
import java.util.Scanner;

import java.util.Calendar;
import java.text.SimpleDateFormat;

public class RinexObsHeader {

    // Need to know when we have finished reading the header 
    //private static int eohFlag = 0;
    private static int obsTimeFlag = 1;
    private static int getSatsFlag = 0;
    private static int numObs = 0;
    private static int epochNumObs = 0;
    private static int epoch;
    private static int numObsTypes = 0;
    private static int numOfLines = 0;
    private static int numOfLinesRead = 0;
    private static StringUtils util;
    private static String obsTypes[];
    
    private static String versionVal;
    private static String fileType;
    private static String system;

    private static String fileProgram;
    private static String fileAgency;
    private static String fileDate;
    private static String markerNumber;
    private static String markerName;
    private static String observer;
    private static String agency;

    private static String recNo;
    private static String recType;
    private static String recVers;

    private static String antType;
    private static String antNo;

    private static String xApprox;
    private static String yApprox;
    private static String zApprox;

    private static String hAntOffset; 
    private static String eAntOffset; 
    private static String nAntOffset; 
   
    private static String interval;
    private static long startDate;

    private static GPSTime sT;
    private static GPSTime eT;
 
    RinexObsHeader() {
        epoch = 0;
    }

    private static long parseTime(String line) {
        Integer year  = Integer.parseInt( util.lrtrim(line.substring(0,6)) );
        Integer month = Integer.parseInt( util.lrtrim(line.substring(6,12)) );
        Integer day   = Integer.parseInt( util.lrtrim(line.substring(12,18)) );
        Integer hour  = Integer.parseInt( util.lrtrim(line.substring(18,24)) );
        Integer min   = Integer.parseInt( util.lrtrim(line.substring(24,30)) );
        Integer sec   = Integer.parseInt( util.lrtrim(line.substring(30,35)) );
        String msec   = line.substring(36,43);

        if( month == 0 ) {
            month = 12;
        }
        else {
            month--;
        }
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR,year);
        cal.set(Calendar.MONTH,month);
        cal.set(Calendar.DAY_OF_MONTH,day);
        cal.set(Calendar.HOUR_OF_DAY,hour);
        cal.set(Calendar.MINUTE,min);
        cal.set(Calendar.SECOND,sec);
        cal.set(Calendar.MILLISECOND,0);
        //SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //String returnVal = sdf.format(cal.getTime());
        //System.out.println("SIMPLE Date Format:"+returnVal);
        long diff = cal.getTimeInMillis();
        //System.out.println("DIFF:"+diff); 
        return (diff);
    }

    public static boolean checkEOH(String line) {
        String eohStr            = "END OF HEADER";
        String endOfLine = line.substring(60);
        if( eohStr.matches(endOfLine) ) {
            return true;
        }
        return false;
    }

    //
    // Return the number of Observations Types Reported in the RINEX HEADER
    //
    public static int numObsTypes() {
        return numObsTypes;
    }

    public static void parseHeaderLine(String line) {
        String versionStr        = "RINEX VERSION / TYPE";
        String programStr        = "PGM / RUN BY / DATE";
        String commentStr        = "COMMENT";
        String markerNameStr     = "MARKER NAME";
        String markerNumberStr   = "MARKER NUMBER";
        String observerStr       = "OBSERVER / AGENCY";
        String receiverStr       = "REC # / TYPE / VERS";
        String antennaStr        = "ANT # / TYPE";
        String positionStr       = "APPROX POSITION XYZ";
        String antennaDeltaStr   = "ANTENNA: DELTA H/E/N";
        String wavelengthStr     = "WAVELENGTH FACT L1/2";
        String obsTypesStr       = "# / TYPES OF OBSERV";
        String intervalStr       = "INTERVAL";
        String firstObsStr       = "TIME OF FIRST OBS";
        String lastObsStr        = "TIME OF LAST OBS";
        String receiverOffsetStr = "RCV CLOCK OFFS APPL";
        String leapSecondsStr    = "LEAP SECONDS";
        String numSatsStr        = "# OF SATELLITES";
        String prnObsStr         = "PRN / # OF OBS";
        String eohStr            = "END OF HEADER";


        int length = line.length();
        if(length > 60 ) {
            String endOfLine = line.substring(60);
   
            if( versionStr.matches(endOfLine) ) {
                versionVal = util.lrtrim(line.substring(0,20));
                fileType   = util.lrtrim(line.substring(20,40));
                system     = util.lrtrim(line.substring(40,60));
            } 
            else if( programStr.matches(endOfLine) ) {
                fileProgram = util.lrtrim(line.substring(0,20));
                fileAgency  = util.lrtrim(line.substring(20,40));
                fileDate    = util.lrtrim(line.substring(40,60));
            }
            else if ( commentStr.matches(endOfLine) ) {
                String comment = util.lrtrim(line.substring(0,60));
                //System.out.println("Comment    :"+ comment );
            }
            else if ( markerNameStr.matches(endOfLine) ) {
                markerName = util.lrtrim(line.substring(0,60));
            }
            else if ( markerNumberStr.matches(endOfLine) ) {
                markerNumber = util.lrtrim(line.substring(0,20));
            }
            else if ( observerStr.matches(endOfLine) ) {
                observer = util.lrtrim(line.substring(0,20));
                agency   = util.lrtrim(line.substring(20,60));
            }
            else if ( receiverStr.matches(endOfLine) ) {
                recNo   = util.lrtrim(line.substring(0,20));
                recType = util.lrtrim(line.substring(20,40));
                recVers = util.lrtrim(line.substring(40,60));
            }
            else if ( antennaStr.matches(endOfLine) ) {
                antNo   = util.lrtrim(line.substring(0,20));
                antType = util.lrtrim(line.substring(20,40));
            }
            else if ( positionStr.matches(endOfLine) ) {
                xApprox = util.lrtrim(line.substring(0,14));
                yApprox = util.lrtrim(line.substring(14,28));
                zApprox = util.lrtrim(line.substring(28,42));
            }
            else if ( antennaDeltaStr.matches(endOfLine) ) {
                hAntOffset = util.lrtrim(line.substring(0,14));
                eAntOffset = util.lrtrim(line.substring(14,28));
                nAntOffset = util.lrtrim(line.substring(28,42));
            }
            else if ( wavelengthStr.matches(endOfLine) ) {
                //System.out.println(line);
            }
            else if ( obsTypesStr.matches(endOfLine) ) {
                numObsTypes = Integer.parseInt(util.lrtrim(line.substring(4,6)));
                //System.out.println("ObsType :"+numObsTypes);
                obsTypes = new String[numObsTypes];
                Integer start = 10;
                Integer end = 12;
                for( int i = 0; i < numObsTypes; i++) {
                    obsTypes[i] = util.lrtrim(line.substring(start,end));
                    //System.out.println("OBS "+i+":"+obsTypes[i]);
                    start = start +6;
                    end = end + 6;
                }
            }
            else if ( intervalStr.matches(endOfLine) ) {
                interval = util.lrtrim(line.substring(0,10));
            }
            else if ( firstObsStr.matches(endOfLine) ) {
                //System.out.println(line);
                //long dateString = parseTime(line);
                startDate = parseTime(line);
                //System.out.println("Start Time :"+dateString);
                //GPSTime sT = new GPSTime(); 
                System.out.println("Start Time :"+startDate);
                sT = new GPSTime(); 
                //long value = time.utc2GpsWeek(dateString);
                //System.out.println("Start Time :"+dateString);
            }
            else if ( lastObsStr.matches(endOfLine) ) {
                //System.out.println(line);
                long dateString = parseTime(line);
                //System.out.println("Last Time :"+dateString);
            }
            else if ( leapSecondsStr.matches(endOfLine) ) {
                //System.out.println(line);
                String leapSeconds = util.lrtrim(line.substring(0,6));
                //System.out.println("Leap Seconds :"+ leapSeconds);
            }
            else if ( numSatsStr.matches(endOfLine) ) {
                //System.out.println(line);
                String numSVs = util.lrtrim(line.substring(0,6));
                //System.out.println("Number of Sats :"+ numSVs);
            }
            else if( prnObsStr.matches(endOfLine) ) {
                System.out.println(line);
            }
            //else if( eohStr.matches(endOfLine) ) {
                // no need to look for RINEX header information anymore
                // time to get some data
            //    eohFlag = 1;
            //}
        }
   }

    public String getVersionVal() {
        return versionVal;
    }

    public String getFileType() {
        return fileType;
    }

    public String getSystem() {
        return system;
    }

    public String getFileProgram() {
        return fileProgram;
    }

    public String getFileAgency() {
        return fileAgency;
    }

    public String getFileDate() {
        return fileDate;
    }

    public String getMarkerNumber() {
        return markerNumber;
    }
    
    public String getMarkerName() {
        return markerName;
    }

    public String getObserver() {
        return observer;
    }

    public String getAgency() {
        return agency;
    }

    public String getRecNo() {
        return recNo;
    }

    public String getRecType() {
        return recType;
    }

    public String getRecVers() {
        return recVers;
    }

    public String getAntType() {
        return antType;
    }

    public String getAntNo() {
        return antNo;
    }

    public String getXApprox() {
        return xApprox;
    }

    public String getYApprox() {
        return yApprox;
    }

    public String getZApprox() {
        return zApprox;
    }

    public String getHAntOffset() {
        return hAntOffset;
    }

    public String getEAntOffset() {
        return eAntOffset;
    }

    public String getNAntOffset() {
        return nAntOffset;
    }

    public String getInterval() {
        return interval;
    }

    public Integer getNumOfObsTypes() {
        return numObsTypes;
    }

    public long getStartDate() {
        return startDate;
    }

    public int obs2index(String obsType) {
        String temp;
        for( int i = 0; i < numObsTypes; i++) {
            temp = obsTypes[i];
            if(temp.matches(obsType)) {
                return i;
            }
        }
        System.err.println("The obs Type: "+obsType+" does not exist in this RINEX File"); 
        return -1;
    }

    public int printHeaderMetaData() {
        System.out.println("Rinex Version     : " + getVersionVal() );
        System.out.println("File Type         : " + getFileType() );
        System.out.println("System            : " + getSystem() );

        System.out.println("fileProgram       : " + getFileProgram() );
        System.out.println("fileAgency        : " + getFileAgency() );
        System.out.println("fileDate          : " + getFileDate() );

        System.out.println("markerName        : " + getMarkerName() );
        System.out.println("markerNumber      : " + getMarkerNumber() );
    
        System.out.println("observer          : " + getObserver() );
        System.out.println("agency            : " + getAgency() );
   
        System.out.println("receiver Type     : " + getRecType() ); 
        System.out.println("receiver No       : " + getRecNo() ); 
        System.out.println("receiver Version  : " + getRecVers() ); 

        System.out.println("antenna Type      : " + getAntType() );
        System.out.println("antenna No        : " + getAntNo() );

        System.out.println("Approximate Coords: " + getXApprox() + " "+ getYApprox()+" "+getZApprox() );
        System.out.println("Antenna Offsets   : " + getNAntOffset()+" " + getEAntOffset() + " " + getHAntOffset() );

        System.out.println("Data Interval     : " + getInterval() );
        System.out.println("Num of Obs Types  : " + getNumOfObsTypes() );
        System.out.print("Obs Types         :");
        for( int i = 0 ; i < getNumOfObsTypes() ; i++) {
            System.out.print(" "+obsTypes[i]);
        }
        System.out.println();

        GPSTime time = new GPSTime(getStartDate()); 
        long value = time.utc2GpsWeek( getStartDate() );
        System.out.println();
        System.out.println("startDate         : " + getStartDate() );
        System.out.println("Start of Obs      : " + value);
        System.out.println("Start of Obs      : " + sT.dateString() );
        System.out.println();
        System.out.println();
        return 1;
    }
}



